require 'open-uri'
require 'hpricot'

module TalkShoe
  class Connection
    
    def self.default_options
      { :base_url =>  'http://api.talkshoe.com/TalkShoeServices/services/'}
    end
    
    def self.valid_methods
      {
        'TalkcastService' => ['getLiveShows', 'getUpcomingShows', 'getTalkcastInformation', 'getEpisodes']
      }
    end
    
    attr_reader :url, :xml
    
    def initialize(options = {})
      @url = build_url(Connection.default_options.merge(options))
    end
    
    def xml
      @xml ||= fetch_xml
    end
    
    def fetch_xml
      begin
        open(url) do |f|
          doc = Hpricot.XML(f)
          error = doc.at('/soapenv:Reason/soapenv:Text')
          raise ArgumentError(error.text) unless error.nil?
          return f.string
        end
      rescue OpenURI::HTTPError => e
        raise "Error making connection to TalkShoe server at \"#{url}\""
      end
    end
    
    def build_url(options)
      raise ArgumentError.new('options cannot be nil') if options.nil?
    
      service = options.delete(:service_name)
      raise ArgumentError.new('options must include a :service_name') if service.nil?
      raise ArgumentError.new("invalid service_name: #{service}") unless Connection.valid_methods.keys.include?(service)
    
      method = options.delete(:method_name)
      raise ArgumentError.new('options must include a :method_name') if method.nil?
      raise ArgumentError.new("invalid method_name: #{method}") unless Connection.valid_methods[service].include?(method)
    
      base_url = options.delete(:base_url)
      base_url << '/' unless base_url[-1, 1] == '/'
      url = "#{base_url}#{service}/#{method}"
    
      unless options.empty?
        url = url << options.inject('') do |params, (key, value)|
          "#{params.blank? ? '?' : '&'}#{key}=#{value}"
        end
      end
    
      url
    end
    
    private :build_url, :url, :fetch_xml
    
  end
end